/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/userdata/UserdataHandler.cpp,v 1.6 2003/11/21 16:12:58 itsme Exp $
 *
 *
 *  this is the main userdata message handler, it dispatches messags
 *  to their register UDC Clients, which include:
 *     - UDCAutoAnswer
 *     - UDCLicenseHandler
 *     - UDCPinger
 *     - DiffieHellmanHandler
 *
 */

#include "CPhone.h"
#include <windows.h>        // windows.h must be after cphone.h

#include "PhoneOptions.h"

#include "spipc.h"
#include "spif.h"
#include "UserdataHandler.h"
#include "debug.h"

#define TIMERBASE 123

UserdataHandler::UserdataHandler(CDialog& dlg) : m_dlg(dlg)
{
    m_bUserdataChannelIsSecure= false;
    InitializeCriticalSection(&m_lock);
}
UserdataHandler::~UserdataHandler()
{
    for (ClientToTimerMap::iterator i= m_udClientTimers.begin() ; i!=m_udClientTimers.end() ;  ++i)
        m_dlg.KillTimer((*i).second);

    DeleteCriticalSection(&m_lock);
}


// this method is called from the SPIPC message handler
bool UserdataHandler::HandleUserData(DWORD dwId, const ByteVector& data)
{
    if (data.empty())
    {
        debug("ERROR: received empty userdata message\n");
        return false;
    }
    BYTE headerbyte= data[0];

    debug("UD: ud message %02x,  %d databytes\n", headerbyte, data.size()-1);
    if (isSecureChannelMessage(headerbyte) && ! m_bUserdataChannelIsSecure)
    {
        debug("ERROR: received securestate message in insecure state\n");
        return false;
    }

    ClientToUDMap::iterator handler_i= m_udHandlers.find(UD_CLIENT(headerbyte));
    if (handler_i!=m_udHandlers.end())
        return (*handler_i).second->HandleUserdataMessage(data);

    debug("ERROR: cannot find handler for client %02x\n", UD_CLIENT(headerbyte));
    return false;
}



bool UserdataHandler::SendSingleMessage(const ByteVector& data)
{
    if (data.empty())
    {
        debug("ERROR: sendsinglemessage called with empty message, probably racecondition with stopsending\n");
        return false;
    }
    debug("UDC: sending single message %02x  of %d bytes\n", data[0], data.size());
    int res= SP_sendUserData(data);
    if( res!=E_SPIPC_OK )
    {
        debug("ERROR in SP_sendUserData: %08lx %hs\n", res, SPIPCResult(res));
        return false;
    }
    return true;
}

bool UserdataHandler::StopStateMessage(UDCLIENTID client)
{
    EnterCriticalSection(&m_lock);

    ClientToMsgMap::iterator msg_i= m_udClientMessages.find(client);
    if (msg_i!=m_udClientMessages.end())
    {
        ClientToTimerMap::iterator tmr_i= m_udClientTimers.find(client);
        if (tmr_i!=m_udClientTimers.end()) 
        {
            DWORD hTmr= m_udClientTimers[client];
            m_dlg.KillTimer(hTmr);

            m_udTimerClient.erase(hTmr);
            m_udClientTimers.erase(client);
        }

        m_udClientMessages.erase(client);
        m_udClientMessageCount.erase(client);

        debug("UD: killed old state message timer for client-%x\n", client);
    }

    LeaveCriticalSection(&m_lock);

    return true;
}


// count==-1  means send an infinite nr of messages
// interval==0 || data.empty() : stop sending messages
bool UserdataHandler::SendStateMessage(UDCLIENTID client, const ByteVector& data, int interval /*=1000*/, int count /*=-1*/)
{
    if (data.empty())
        debug("ud: stop sending messages for client-%x\n", client);
    else
        debug("ud: sending state message %02x for client-%x\n", data[0], client);

    // stop old timer for this client
    StopStateMessage(client);

    if (data.empty())
    {
        debug("UD: no more state message for client-%x\n", client);
        return true;
    }
    if (count==0)
    {
        debug("UD: sending zero messages for client-%x\n", client);
        return true;
    }

    EnterCriticalSection(&m_lock);

    // register new message for this client
    m_udClientMessages[client]= data;
    m_udClientMessageCount[client]= count;

    // send first message
    SendSingleMessage(data);
    if (m_udClientMessageCount[client]>0)
        --m_udClientMessageCount[client];

    // if interval!=0, resend every <interval> msec
    if (m_udClientMessageCount[client]!=0 && interval>0) 
    {
        DWORD hTmr= m_dlg.SetTimer(client+1000, interval, UserdataHandler::staticTimerProc);
        m_udClientTimers[client]= hTmr;
        m_udTimerClient[hTmr]= client;

        debug("UD: started sending state messages for client-%x  t=%08lx at %d\n", client, m_udClientTimers[client], GetTickCount());
    }

    LeaveCriticalSection(&m_lock);  

    return true;
}

void UserdataHandler::StopAll()
{
    for (ClientToUDMap::iterator i= m_udHandlers.begin() ; i!=m_udHandlers.end() ;  ++i)
        (*i).second->StopSending();
}

bool UserdataHandler::UnRegisterUserdataHandler(UDCLIENTID client)
{
    debug("UD: unregistering client-%x\n", client);
    return 1==m_udHandlers.erase(client);
}


bool UserdataHandler::RegisterUserdataHandler(UDCLIENTID client, UDClientHandler* handler)
{
    debug("UD: registering client-%x\n", client);
    return m_udHandlers.insert(ClientToUDMap::value_type(client, handler)).second;
}



void CALLBACK UserdataHandler::staticTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    theApp.m_ud->TimerProc(hwnd, uMsg, idEvent, dwTime);
}



void UserdataHandler::TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    EnterCriticalSection(&m_lock);

    UDCLIENTID client= m_udTimerClient[idEvent];
    ByteVector msg= m_udClientMessages[client];

    debug("UD: sending timer message for client-%x t=%08lx  at %d\n", client, idEvent, GetTickCount());

    if (m_udClientMessageCount[client]>0)
        --m_udClientMessageCount[client];

    bool bStopSending = (m_udClientMessageCount[client]==0);

    LeaveCriticalSection(&m_lock);

    SendSingleMessage(msg);

    if (bStopSending)
        StopStateMessage(client);
}


void UserdataHandler::EnableSecureMode()
{
    m_bUserdataChannelIsSecure= true;
}

